package com.roadmap.client.module.plan;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import com.roadmap.client.module.BaseManager;
import com.roadmap.common.BaseConst;
import com.roadmap.common.BaseEntity;
import com.roadmap.common.RdcLogger;
import com.roadmap.entities.LifeGoal;
import com.roadmap.entities.LifePlan;
import com.roadmap.entities.Milestone;
import com.roadmap.exception.*;

public class MilestoneManager extends BaseManager {
	private final static Logger logger = RdcLogger
			.getLogger(MilestoneManager.class);

	public MilestoneManager(String aspirantId, LifePlan parent) {
		super(aspirantId, Milestone.class, parent);
	}

	@Override
	public void create(BaseEntity entity) throws NullObjectException,
			InvalidActionException, InvalidValueException, ServerException,
			EntityNotFoundException, ActionNotSupportedException,
			InvalidStatusException {
		if (!checkEntityIsValid(entity))
			return;

		LifeGoal goal = getGoalOfStone();
		/*
		 * only when the goal's status is SCHEDULED or UNDERGOING and all
		 * milestones of the plan doesn't occupy 100%, can a new milestone be
		 * created.
		 */
		if (goal.getStatus() == BaseConst.LIFEGOAL_STATUS_SCHEDULED
				|| goal.getStatus() == BaseConst.LIFEGOAL_STATUS_UNDERGOING) {
			getDbUtil().save(entity);
		}
		else {
			ActionNotSupportedException anse = new ActionNotSupportedException();
			String msg = "The current status of the goal doesn't support this action.";
			logger.error(msg, anse);
			throw anse;
		}
	}

	private LifeGoal getGoalOfStone() throws NullObjectException,
			InvalidQueryException, ServerException, InvalidValueException,
			EntityNotFoundException {
		LifePlan plan = (LifePlan) getParent();
		LifeGoal goal = (LifeGoal) getDbUtil().getEntityById(LifeGoal.class,
				plan.getGoalId());
		if (goal == null) {
			EntityNotFoundException enfx = new EntityNotFoundException();
			logger.error("No goal was found the plan.", enfx);
			throw enfx;
		}

		return goal;
	}

	///** calculate the proportion all milestones occupy in the plan */
	// private int sumarizeStones() throws NullObjectException,
	// InvalidQueryException, ServerException, InvalidValueException {
	//
	// List<BaseEntity> list = (List<BaseEntity>) getEntitiesOfParent();
	// Iterator<BaseEntity> iter = list.iterator();
	// int sum = 0;
	// while (iter.hasNext()) {
	// Milestone stone = (Milestone) iter.next();
	// sum += stone.getProportionOfPlan();
	// }
	// return sum;
	// }
	//
	// private Milestone getLastStoneInDBOfParent() throws NullObjectException,
	// InvalidQueryException, ServerException, InvalidValueException {
	// StringBuffer hsql = new StringBuffer(getParentIdName());
	// hsql.append("='");
	// hsql.append("getParent().getId()");
	// hsql.append("' and porportionOfPlan >= max(porportionOfPlan)");
	// List list = getDbUtil().getEntitiesByCriteria(getManagedEntityType(),
	// hsql.toString());
	// return (Milestone) list.get(0);
	//	}

	/* To complete a milestone, change its status to SATISFIED */
	@Override
	public void complete(BaseEntity entity) throws NullObjectException,
			InvalidActionException, InvalidValueException, ServerException,
			EntityNotFoundException, ActionNotSupportedException {
		if (!checkEntityIsValid(entity))
			return;

		Milestone stone = (Milestone) entity;
		if (stone.getStatus() == BaseConst.MILESTONE_STATUS_UNSATISFIED
				&& stone.getPlanId().equals(getParent().getId())) {
			stone.setStatus(BaseConst.MILESTONE_STATUS_SATISFIED);
			getDbUtil().update(stone);
		}
		else {
			ActionNotSupportedException anse = new ActionNotSupportedException();
			String msg = "The action is not supported. Check the milestone to be updated.";
			logger.error(msg, anse);
			throw anse;
		}
	}

	/*
	 * All milestones of a plan are divided to two parts: one part is got from
	 * database, this part occupies the proportion which must be smaller than
	 * 100%; The second part is a virtual one which is not recorded in database,
	 * it's a 100% one, namely the last one
	 */
	@Override
	public List<BaseEntity> getEntitiesOfParent() throws NullObjectException,
			InvalidQueryException, ServerException, InvalidValueException {
		LifePlan plan = (LifePlan) getParent();
		if (plan == null || plan.getId() == null) {
			NullObjectException noe = new NullObjectException(
					"the entity can't be NULL");
			logger.error(noe);
			throw noe;
		}

		List<BaseEntity> milestones = new ArrayList<BaseEntity>();

		// the returned milestones will be ordered by proporationOfPlan from
		// small to big. when a big milestone is satisfied, the ones smaller
		// than it must be satisfied, too
		StringBuffer criteria = new StringBuffer("planId='");
		criteria.append(plan.getId());
		criteria.append("' order by proportionOfPlan ASC");
		List<BaseEntity> list = (List<BaseEntity>) getDbUtil()
				.getEntitiesByCriteria(Milestone.class, criteria.toString());
		if (list != null && list.size() > 0)
			milestones.addAll(list);

		// once a plan is created, it already has one milestone which are
		// the start of the plan
		Milestone last = new Milestone();
		last.setPlanId(plan.getAspirantId());
		last.setProportionOfPlan(100);
		last.setStoneDate(plan.getScheduledEndDate());
		milestones.add(last);

		return milestones;
	}

}
